#include <termios.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <string.h>
#include <jni.h>

#include "android/log.h"

#include "utiledef.h"


#define UART_DEVICE1     "/dev/ttyS1"




void logHexstring(int len,char *buf)
{
	int i;
	char tmpbuf[1000];
	char logbuf[100];

	memset(tmpbuf,0x00,1000);

	for(i=0;i<len;i++)
	{
		memset(logbuf,0x00,100);
		sprintf(logbuf,"%02X ",buf[i]);
		strcat(tmpbuf,logbuf);
	}
	LOGD("%s",tmpbuf);
}
//????????,???��??,?????��??????????,?????????
//????????,????,???????

static speed_t serialport_getBaudrate(long baudrate)
{
	switch(baudrate) {
	case 0: return B0;
	case 50: return B50;
	case 75: return B75;
	case 110: return B110;
	case 134: return B134;
	case 150: return B150;
	case 200: return B200;
	case 300: return B300;
	case 600: return B600;
	case 1200: return B1200;
	case 1800: return B1800;
	case 2400: return B2400;
	case 4800: return B4800;
	case 9600: return B9600;
	case 19200: return B19200;
	case 38400: return B38400;
	case 57600: return B57600;
	case 115200: return B115200;
	case 230400: return B230400;
	case 460800: return B460800;
	case 500000: return B500000;
	case 576000: return B576000;
	case 921600: return B921600;
	case 1000000: return B1000000;
	case 1152000: return B1152000;
	case 1500000: return B1500000;
	case 2000000: return B2000000;
	case 2500000: return B2500000;
	case 3000000: return B3000000;
	case 3500000: return B3500000;
	case 4000000: return B4000000;
	default: return -1;
	}
}



void serialport_set_speed(int fd, int speed){
	int   i;
	int   status;
	struct termios   Opt;
	tcgetattr(fd, &Opt);
	cfsetispeed(&Opt, 9600);
	tcflush(fd,TCIOFLUSH);
}


/**
 *@brief   ???????????��????��??��??��
 *@param  fd     ????  int  ????????????
 *@param  databits ????  int ????��   ?? ?5,6,7????8
 *@param  stopbits ????  int ??��   ??? 1 ????2
 *@param  parity  ????  int  ��?????? ???N,E,O,,S
 */

#if 0
int serialport_set_Parity(int fd,int databits,int stopbits,int parity)
{
	struct termios options;
	int speed;

	if  ( tcgetattr( fd,&options)  !=  0) {
		perror("SetupSerial 1");
		return(1);
	}
	options.c_cflag &= ~CSIZE;
	switch (databits) // ????????��??
	{
	case 5:
		options.c_cflag |= CS5;
		break;
	case 6:
		options.c_cflag |= CS6;
		break;
	case 7:
		options.c_cflag |= CS7;
		break;
	case 8:
		options.c_cflag |= CS8;
		break;
		//	default:
		//fprintf(stderr,"Unsupported data size\n"); return (FALSE);
	}
	switch (parity)
	{
	case 'n':
	case 'N':
		options.c_cflag &= ~PARENB;    //Clear parity enable
		options.c_iflag &= ~INPCK;     // Enable parity checking
		break;
	case 'o':
	case 'O':
		options.c_cflag |= (PARODD | PARENB); // ???????��??
		options.c_iflag |= INPCK;             // Disnable parity checking
		break;
	case 'e':
	case 'E':
		options.c_cflag |= PARENB;     // Enable parity
		options.c_cflag &= ~PARODD;    //?????��??
		options.c_iflag |= INPCK;       // Disnable parity checking
		break;
	case 'S':
	case 's'://  as no parity
		options.c_cflag &= ~PARENB;
		options.c_cflag &= ~CSTOPB;break;
	default:
		//printf(stderr,"Unsupported parity\n");
		return (1);
	}
	//??????��
	switch (stopbits)
	{
	case 1:
		options.c_cflag &= ~CSTOPB;
		break;
	case 2:
		options.c_cflag |= CSTOPB;
		break;
	default:
		//fprintf(stderr,"Unsupported stop bits\n");
		return (1);
	}

	// Set input parity option
	if (parity != 'n')
		options.c_iflag |= INPCK;
	tcflush(fd,TCIFLUSH);
	//options.c_cc[VTIME] = 150;  //???��??15 seconds
	options.c_cc[VTIME] = 10;  //???��?? seconds
	options.c_cc[VMIN] = 0;  //Update the options and do it NOW

	cfsetispeed(&options, 9600);
	cfsetospeed(&options, 9600);


	if (tcsetattr(fd,TCSANOW,&options) != 0)
	{
		perror("SetupSerial 3");
		return (1);
	}
	options.c_lflag  &= ~(ICANON | ECHO | ECHOE | ISIG); // Input
	options.c_oflag  &= ~OPOST;  // Output
	return (0);
}





int serialport_open(void)
{
	int fd;
	fd=open(UART_DEVICE1, O_RDWR | O_NOCTTY|O_NDELAY);
	fcntl(fd,F_SETFL,0);
	return fd;


}
int serialport_close(int fd)
{
	close(fd);
	return 0;
}




HANDLE OpenComm(int comm,long baud)
{
	int fd;

#if COM_DEBUG
	   LOGE("serialport_open ");
#endif
		fd=serialport_open();
        if (fd < 0)
		{
#if COM_DEBUG
        	LOGE("serialport_open error");
#endif
            return -1;
        }

        if (serialport_set_Parity(fd,8,1,'n') == 1)
		{
#if COM_DEBUG
        	LOGE("Set Parity Error\n");
#endif
            return -1;
        }
      //  serialport_set_speed(fd,B9600);
#if COM_DEBUG
        LOGE("serialport_open ok %d", fd);
#endif
        return fd;
}

#endif

static char sport[100]={"/dev/ttyS1"};

//static HANDLE UHF_HANDLER=0;

void Set_SerialPort(char *p)
{
	memset(sport,0x00,100);
	strcpy(sport,p);
}

HANDLE OpenComm(int comm,long baud)
{
	int fd;
	speed_t speed;

	/* Check arguments */
	{
		speed = serialport_getBaudrate(baud);
		if (speed == -1) {
			/* TODO: throw an exception */
#if COM_DEBUG
			LOGE("Invalid baudrate");
#endif
			return -1;
		}
	}

	/* Opening device */
	{
		//jboolean iscopy;
		//const char *path_utf = (*env)->GetStringUTFChars(env, path, &iscopy);
		//LOGD("Opening serial port %s with flags 0x%x", path_utf, O_RDWR | flags);
		fd = open(sport, O_RDWR );
		//LOGD("open() fd = %d", fd);
		//(*env)->ReleaseStringUTFChars(env, path, path_utf);
		if (fd == -1)
		{
			/* Throw an exception */
#if COM_DEBUG
			LOGE("Cannot open port");
#endif
			/* TODO: throw an exception */
			return -1;
		}
	}

	/* Configure device */
	{
		struct termios cfg;
#if COM_DEBUG
		LOGD("Configuring serial port");
#endif
		if (tcgetattr(fd, &cfg))
		{
#if COM_DEBUG
			LOGE("tcgetattr() failed");
#endif
			close(fd);
			/* TODO: throw an exception */
			return -1;
		}

		cfmakeraw(&cfg);
		cfsetispeed(&cfg, speed);
		cfsetospeed(&cfg, speed);

		cfg.c_cc[VTIME] = 1; /* ???��??200ms seconds*/   //超时时间单位100MS,5*100
		cfg.c_cc[VMIN] = 0; /* Update the options and do it NOW */

		if (tcsetattr(fd, TCSANOW, &cfg))
		{
#if COM_DEBUG
			LOGE("tcsetattr() failed");
#endif
			close(fd);
			/* TODO: throw an exception */
			return -1;
		}
	}
	//UHF_HANDLER=fd;
	return fd;
}
int CloseComm(HANDLE icdev)
{
	close(icdev);
	return 0;
}

int ReadChar(HANDLE icdev, uchar * a)
{
	uchar  receive_buf[256];
	int res;



	res = read(icdev, receive_buf,1);
	if(res>0)
	{
		a[0]=receive_buf[0];
		return 1;
	}	
	else
	{
		return 0;	
	}	
}
int ReceiveST(HANDLE icdev,uchar *a)
{
	
	    int i;
	//uchar s;

    for(i=0;i<3;i++)
    {
	   ReadChar(icdev,a);
		
	   if(*a!=0xa7) continue;
	   return (0);
	}
	if(i>=3)
		return 1;
	return 0;
}

int  WriteChar_N(HANDLE icdev,int len,uchar *sendbuf)
{
	int i;

#if COM_DEBUG
	LOGD("Send Data :");
	logHexstring(len,sendbuf);
#endif

	return write(icdev,sendbuf,len);

	return 0;
}


int ReadChar_N(HANDLE icdev,uchar *rlen,uchar *rebuf)
{
		uchar len=0;
	uchar LRC=0;  //???��???
	int i;
	uchar t=0,rt=0;

	//?????????
#if COM_DEBUG
	LOGD("Recv Start");
#endif
	if(ReceiveST(icdev,&t))
	{
#if COM_DEBUG
		LOGE("Recv Time Out");
#endif
		return (-132);//???????
	}

	LRC=t;

#if COM_DEBUG
	LOGD("RecvData ");
#endif
	//???????????
	rt=ReadChar(icdev,&len);
	if(rt!=1)
	{

		return 1;
	}
	LRC=LRC^len;
	for(i=0;i<=len;i++)
	{
		rt=ReadChar(icdev,&rebuf[i]);
		if(rt!=1)
		{
			return 2;
		}
	}

	for(i=0;i<len;i++)
	{
		LRC=LRC^rebuf[i];
	}

#if COM_DEBUG
    LOGD("read dataok :");
    logHexstring(len,rebuf);
#endif

	if((t!=0xA7)||(LRC!=rebuf[len]))
	{
		return 3;
	}

	if(rebuf[0]!=0)
    {
	    return rebuf[0];
    }

	rlen[0]=len;


	return 0;

}




int PurgeComm(HANDLE icdev,int a)
{
	if(a==PURGE_TXCLEAR)
	{
		tcflush(icdev, TCOFLUSH);     //����������
	}
	if(a==PURGE_RXCLEAR)
	{
		tcflush(icdev, TCIFLUSH);    //������뻺��
	}

	return 0;
}


int RSU_WriteChar(HANDLE icdev,uchar a)
{
	uchar  send_buf[256] ;
	send_buf[0]=a;

//#if COM_DEBUG
//	LOGD("%02X ",a);
//#endif
	return write(icdev,send_buf,1);
//	return WriteChar(icdev,a);

}

//��ת��
int RSU_WriteChar_Data(HANDLE icdev,uchar tmpa)
{
    if(tmpa==0xff)
    {
        tmpa=0xfe;
        RSU_WriteChar(icdev,tmpa);

        tmpa=0x01;
        RSU_WriteChar(icdev,tmpa);

    }
    else if(tmpa==0xfe)
    {
        tmpa=0xfe;
        RSU_WriteChar(icdev,tmpa);

        tmpa=0x00;
        RSU_WriteChar(icdev,tmpa);
        //chksum=chksum ^tmpa;

    } else{

        RSU_WriteChar(icdev,tmpa);
        //chksum=chksum ^tmpa;
    }


}

int RSU_ReceiveST(HANDLE icdev,uchar *a)
{

	int i;
	//uchar s;

	for(i=0;i<7;i++)
	{
		ReadChar(icdev,a);

		if(*a!=0xFF) continue;//?��???????????????????0xA7
		return (0);
	}
	if(i>=3)
		return 1;
	return 0;
}


//����ת��
int  RxEscapingFunc(uint8_t * _pInBuf, uint16_t _Inlen, uint8_t* _pOutBuf, uint16_t* _pOutLen)
{
	uint16_t i;
	uint16_t j = 0;
	int ret = 0;

	if(_Inlen >= 300)        //�жϳ����Ƿ�Ϸ�
	{
		return -12;
	}
	for(i=0; i<_Inlen; i++)
	{
		if(_pInBuf[i] == 0xFE)
		{
			i++;
			if(_pInBuf[i] == 0x00)
			{
				_pOutBuf[j++] = 0xfe;
			}
			else if(_pInBuf[i] == 0x01)
			{
				_pOutBuf[j++] = 0xff;
			}
			else	//û�и�ת������  ���ش���
			{
				ret = -10;
				break;
			}
		}
		else if(_pInBuf[i] == 0XFF)     //���ִ�������
		{
			ret = -11;
			break;
		}
		else
		{
			_pOutBuf[j++] = _pInBuf[i];
		}
	}
	if(ret == 0)
	{
		*_pOutLen = j;
	}

	return ret;
}

int RSUMODE_ReadChar_N(HANDLE icdev,int *rlen,uchar *rebuf,int TimeOut)
{
	uchar len=0;
	uchar LRC=0;  //???��???
	int i;
	uchar t=0,rt=0;
	uchar tempa;
	uchar chksum=0;
	int inptr=0;
    uchar Databuf[300];
#if COM_DEBUG
	LOGD("Recv Start");
#endif

	inptr=0;
	chksum=0;
	rlen[0]=0;
	memset(rebuf,0xff,10);
	if(RSU_ReceiveST(icdev,&t))
	{
#if COM_DEBUG
		LOGE("Recv Time Out");
#endif
		return (-132);//???????
	}


	while(1) {
		rt = ReadChar(icdev, &tempa);
		if (rt != 1) {
			return -1;
		}


		if (tempa == 0xff) {        //2��Ҳ��ΪOK����������2FF ,������,������
			if (t != 0xff)    //���ж���һ���ַ��ǲ���FF,��FF,�п����ǿ�ʼ������2��FF�ǿ�ʼ����֤���ݵĻ���һ��FFҲ��Ϊ�ǿ�ʼ
			{
				//��һ���ַ���0xff,��Ϊ����
				int retvalue= RxEscapingFunc(Databuf,inptr,rebuf,rlen);
#if COM_DEBUG
              // LOGD("rec data 1  :");
                //logHexstring(inptr,Databuf);
                LOGD("rec data 2  :");
                logHexstring(rlen[0],rebuf);
#endif

				return retvalue;


			}
		} else {
			//�����һ���ֽ���FF,�����յ���һ���ֽڣ�����Ϊ�ǿ�ʼ��������
            Databuf[inptr] = tempa;
			//chksum=chksum^tempa;
			t = tempa;            //���汾�Σ��´����ж�
			if (inptr < 300) {
				inptr++;
			} else {

				return -3;
			}
		}
	}
}

int  RSUMODE_WriteChar_N(HANDLE icdev,int len,uchar *sendbuf)
{
	int i;
	uchar chksum=0;
	uchar tmpa;
    uchar Databuf[300];

#if COM_DEBUG
	LOGD("Send Data :");
#endif
	int data_ptr=0;

	PurgeComm(icdev,PURGE_TXCLEAR);

	PurgeComm(icdev,PURGE_RXCLEAR);

	Databuf[data_ptr]=0xff;data_ptr++;
	Databuf[data_ptr]=0xff;data_ptr++;

    chksum=0;
	for (i=0;i<len;i++){
		tmpa=sendbuf[i];
        chksum=chksum ^tmpa;            //��У����ת��
        if(tmpa==0xff)
		{
			Databuf[data_ptr]=0xfe;data_ptr++;
			Databuf[data_ptr]=0x01;data_ptr++;
		}
		else if(tmpa==0xfe)
		{
			Databuf[data_ptr]=0xfe;data_ptr++;
			Databuf[data_ptr]=0x00;data_ptr++;
		} else
		{
			Databuf[data_ptr]=tmpa;data_ptr++;

		}
	}
	tmpa=chksum;		//校验也要转义
	if(tmpa==0xff)
	{
		Databuf[data_ptr]=0xfe;data_ptr++;
		Databuf[data_ptr]=0x01;data_ptr++;
	}
	else if(tmpa==0xfe)
	{
		Databuf[data_ptr]=0xfe;data_ptr++;
		Databuf[data_ptr]=0x00;data_ptr++;
	} else
	{
		Databuf[data_ptr]=tmpa;data_ptr++;

	}

	Databuf[data_ptr]=0xff;data_ptr++;

	write(icdev,Databuf,data_ptr);



#if COM_DEBUG
    logHexstring(data_ptr,Databuf);
#endif
	return 0;

}






//----------------------------------------------------------------------------------------------------
//固件升级接口,
//----------------------------------------------------------------------------------------------------
//检验字节检验
//不计算头尾
//返回校验值
static char CRC8_1_checkCRC(unsigned char *p)
{
    unsigned int i;
    unsigned int length;
    unsigned char crc = 0;

    length = (p[2] << 8) + p[3];

    for (i = 2; i < length - 3; i++)         //计算校验时，帧头和帧尾不计算
    {
        crc ^= p[i];
    }

    return crc;
}
//检验字节生成
//返回值为CRC8_1校验字节
uint8_t CRC8_1_ProductCRC(uint8_t *p, uint16_t len)
{
    uint16_t i;
    uint8_t crc = 0;

    for (i=2; i<len; i++)         //计算校验时，帧头和帧尾不计算
    {
        crc ^= p[i];
    }

    return crc;
}

int RecvData(int handlers,unsigned char *pbuf,unsigned int timer_out)
{

	int res;

	pbuf[0]=0x00;
	res = read(handlers, pbuf,1);
	if(res>0)
	{
		return 0;		//有数据
	}
	else
	{
		return 1;
	}
}
//发送数据包
int RMUHFRFID_Send_CMD_RFID(int handlers, uchar *payload, uint payload_size)
{
    uint8_t len_h,len_l;
    uint16_t wptr=0;
    uint16_t i,total_len;

    uint8_t checksum=0;

    uint8_t RDTOPC_TX_BUF[2048];


    PurgeComm(handlers,PURGE_TXCLEAR);

    PurgeComm(handlers,PURGE_RXCLEAR);

    total_len=payload_size+7;
    if(total_len >= 2000){
        return -1;
    }


    len_l=(uint8_t)(total_len&0xff);
    len_h=(uint8_t)((total_len>>8)&0xff);

    wptr=0;
    RDTOPC_TX_BUF[wptr++]=0xa5;
    RDTOPC_TX_BUF[wptr++]=0x5a;

    RDTOPC_TX_BUF[wptr++]=len_h;	//H
    RDTOPC_TX_BUF[wptr++]=len_l;	//L

    checksum=0;

    for(i=0;i<payload_size;i++)
    {
        RDTOPC_TX_BUF[wptr++]=payload[i];
    }
    checksum=CRC8_1_ProductCRC(RDTOPC_TX_BUF,total_len-3);
    RDTOPC_TX_BUF[wptr++]=checksum; //CRC
    RDTOPC_TX_BUF[wptr++]=0x0d;
    RDTOPC_TX_BUF[wptr]=0x0a;

#if COM_DEBUG
    LOGD("RMUHFRFID_Send_CMD_RFID data 1  :");
    logHexstring(total_len,RDTOPC_TX_BUF);
#endif
	if(handlers>0)
	{
		write(handlers,RDTOPC_TX_BUF,total_len);
		return 0;
	}

    return -2;
}

#define RFID_HEAD_FIRST                    0xA5
#define RFID_HEAD_SECOND                   0x5A

//֡β
#define RFID_END_MRK_FIRST                 0x0D
#define RFID_END_MRK_SECOND                0x0A

#define RFID_HEAD_LEN                      (2 + 2 + 1)
#define RFID_HEADEND_LEN                   (RFID_HEAD_LEN + 1 + 2)

#define RECVICE_BYTE_TIMEROUT			    10
#define OPERATE_SUCCESS						1
#define OPERATE_FAILD                       0

int RMUHFRFID_Resp_CMD_RFID(int handlers, uchar *inbuf,uint  *inlen, int timer_out)
{

	uint8_t data_buf[2048];
	unsigned int len, i;
	int iRet;
	uchar tmpbyte;
	unsigned char times;

	inlen[0]=0;
	times = 0;
	//RecvData(handlers,&tmpbyte, timer_out);
	while (1)
	{
		iRet = RecvData(handlers,&tmpbyte, timer_out);
		if (iRet != 0)
		{
			times++;
			if (times > timer_out)
			{
				return -1;
			}
		}
		else
		{
			break;
		}
	}
	data_buf[0] = tmpbyte;
	if (data_buf[0] != RFID_HEAD_FIRST)
	{
		return -2;
	}
	iRet = RecvData(handlers,&tmpbyte, RECVICE_BYTE_TIMEROUT);
	if (iRet != 0)
	{
		return -3;
	}
	data_buf[1] = tmpbyte;
	if (data_buf[1] != RFID_HEAD_SECOND)
	{
		return -4;
	}
	iRet = RecvData(handlers,&tmpbyte, RECVICE_BYTE_TIMEROUT);
	if (iRet != 0)
	{
		return -5;
	}
	data_buf[2] = tmpbyte;

	iRet = RecvData(handlers,&tmpbyte, RECVICE_BYTE_TIMEROUT);
	if (iRet != 0)
	{
		return -6;
	}
	data_buf[3] = tmpbyte;
	len = (data_buf[2] << 8) + data_buf[3];
	if (len > 600)
	{
		return -3;
	}

	for (i = 0; i < len - 4; i++)
	{
		iRet = RecvData(handlers,&tmpbyte, RECVICE_BYTE_TIMEROUT);
		if (iRet != 0)
		{
			return -7;
		}
		data_buf[i + 4] = tmpbyte;
	}
	if (data_buf[len - 2] != RFID_END_MRK_FIRST){
		return -8;
	}

	if (CRC8_1_checkCRC(data_buf) != data_buf[len - 3]){
		return -5;
	}

	*inlen = (len - 7)&0x3ff;

	if (*inlen <= 0)			//第一帧是无数据返回的，表示模块进入了连续寻卡模式
	{
		return -100;
	}
#if COM_DEBUG
	LOGD("RMUHFRFID_Resp_CMD_RFID data 1  :");
	logHexstring(len,data_buf);
#endif
	//拷贝有效数据，
	memcpy(inbuf, &data_buf[4], *inlen);

	return 0x00;

}

